﻿using System;
using OverStore.Exceptions.Configuration;
using OverStore.Runtime.OverStoreContext;
using OverStore.Runtime.PersistenceServiceProvider;
using OverStore.Runtime.Storage;
using OverStore.Runtime.ObjectRepository.Mapping;

namespace OverStore.Configuration.ObjectRepository.Mapping
{
    /// <summary>
    /// Produces instances of <see cref="IMapper{TInstance}"/> that uses specified delegates for 
    /// get instance data and apply data to instance.
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    public sealed class DelegateMapperConfiguration<TInstance> : IComponentConfiguration<IMapper<TInstance>>
        where TInstance : class
    {
        /// <summary>
        /// Gets or sets the delegate that convert specified instance <see cref="IRecord"/> object named set of data.
        /// </summary>
        public Func<TInstance, string, IRegistry, object> GetObjectDataFunction { get; set; }

        /// <summary>
        /// Gets or sets the delegate that applies specified data to specified instance.
        /// </summary>
        public Action<TypedRecord, TInstance, IRegistry> ApplyObjectDataFunction { get; set; }

        /// <summary>
        /// Creates instance of <see cref="IMapper{TInstance}"/> with specified configuration.
        /// </summary>
        /// <param name="context">Context contains references to services required for <see cref="IMapper{TInstance}"/> instance.</param>
        /// <returns>
        ///     <see cref="IMapper{TInstance}"/> instance with specified configuration.
        /// </returns>
        public IMapper<TInstance> CreateComponent(IOverStoreContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            if (GetObjectDataFunction == null)
                throw this.ConfigurationException("GetObjectDataFunction is missing.");
            if (ApplyObjectDataFunction == null)
                throw this.ConfigurationException("ApplyObjectDataFunction is missing.");
            return new DelegateMapper<TInstance>(GetObjectDataFunction, ApplyObjectDataFunction);
        }
    }
}